let graphics = {

    imageData: null,
    width: 0,
    height: 0,
    data: null,
    clipRect: null,

    isRectContainPoint(x, y, rect) {
        return x >= rect.x && x <= rect.xMax && y >= rect.y && y <= rect.yMax;
    },

    init(imgData) {
        this.imageData = imgData;
        this.width = imgData.width;
        this.height = imgData.height;
        this.data = imgData.data;
        this.clipRect = cc.rect(0, 0, this.width - 1, this.height - 1);
        this.depthArr = new Array(this.width * this.height);
        this.depthArr.fill(1, 0, this.depthArr.length);

        this.bDepthTest = true; // 是否开启深度缓存
    },

    /**
     * 绘制点. 但是不进行安全检查
     * @param x
     * @param y
     * @param color
     * @private
     */
    _pixel(x, y, color) {
        let ny = this.height - y - 1;
        let idx = ny * this.width * 4 + x * 4;
        this.data[idx] = color.r;
        this.data[idx + 1] = color.g;
        this.data[idx + 2] = color.b;
        this.data[idx + 3] = color.a;
    },

    _pixel3d(x, y, z, color) {
        let ny = this.height - y - 1;
        if (z < this.depthArr[this.width * ny + x]) {
            this.depthArr[this.width * ny + x] = z;
            let idx = ny * this.width * 4 + x * 4;
            this.data[idx] = color.r;
            this.data[idx + 1] = color.g;
            this.data[idx + 2] = color.b;
            this.data[idx + 3] = color.a;
        }
    },

    /**
     * 绘制点, 进行安全检查
     * @param x
     * @param y
     * @param color
     */
    drawPoint(x, y, color) {
        if (debugUtils.debug) {
            debugUtils.checkInteger(x);
            debugUtils.checkInteger(y);
        }
        if (this.isRectContainPoint(x, y, this.clipRect)) {
            this._pixel(x, y, color);
        }
    },

    /**
     * 绘制直线. 包含了裁剪
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @param color
     * @param clipRect
     */
    drawLine(x1, y1, x2, y2, color, clipRect) {
        let v1 = cc.v2(x1, y1);
        let v2 = cc.v2(x2, y2);
        if (this.clipLine(v1, v2, clipRect)) {
            this._line(v1.x, v1.y, v2.x, v2.y, color);
        }
    },

    /**
     *
     * @param v0 {cc.Vec3}
     * @param v1 {cc.Vec3}
     * @param color
     */
    drawLine3d(v0, v1, color) {
        if (this.clipLine3d(v0, v1)) {
            this._line3d(v0, v1, color);
        }
    },

    /**
     * 对 点 v1 v2 进行裁剪
     * @param v1
     * @param v2
     * @param rect
     * @return {boolean} true 表示裁剪成功,更新v1 v2.  false 表示在区域外.
     */
    clipLine(v1, v2, rect) {
        rect = rect || this.clipRect;
        let x1 = v1.x, y1 = v1.y, x2 = v2.x, y2 = v2.y;
        const xMax = rect.xMax;
        const yMax = rect.yMax;
        const xMin = rect.x;
        const yMin = rect.y;

        if (debugUtils.debug) {
            debugUtils.checkInteger(x1);
            debugUtils.checkInteger(y1);
            debugUtils.checkInteger(x2);
            debugUtils.checkInteger(y2);
        }

        // 都在上 下 左 右 一定不裁剪
        if (y1 > yMax && y2 > yMax) {
            return false;
        }
        if (y1 < yMin && y2 < yMin) {
            return false;
        }
        if (x1 < xMin && x2 < xMin) {
            return false;
        }
        if (x1 > xMax && x2 > xMax) {
            return false;
        }

        if (this.isRectContainPoint(x1, y1, rect) && this.isRectContainPoint(x2, y2, rect)) {
            // 不需要裁剪, 取原来的值
            return true;
        }

        if (x1 === x2) {
            // 垂直
            let min_y = Math.min(y1, y2);
            let max_y = Math.max(y1, y2);
            if (min_y > yMax || max_y < yMin) {
                // 视口外
                return false;
            }
            v1.y = cc.math.clamp(y1, yMin, yMax);
            v2.y = cc.math.clamp(y2, yMin, yMax);
            return true;
        }

        if (y1 === y2) {
            // 水平
            let min_x = Math.min(x1, x2);
            let max_x = Math.max(x1, x2);
            if (min_x > xMax || max_x < xMin) {
                return false;
            }
            v1.x = cc.math.clamp(x1, xMin, xMax);
            v2.x = cc.math.clamp(x2, xMin, xMax);
            return true;
        }

        //
        let left_x = Math.min(x1, x2);
        let left_y, right_x, right_y;
        let flip; // 表示是否交换
        if (left_x === x1) {
            left_y = y1;
            right_x = x2;
            right_y = y2;
            flip = false;
        } else {
            left_y = y2;
            right_x = x1;
            right_y = y1;
            flip = true;
        }

        // 令 x 分别为 rect.x 和  rect.xMax
        // P = (1-t) * A + t * B
        // t = (P - A) / (B - A)
        let p1 = (xMin - left_x) / (right_x - left_x);
        let p2 = (xMax - left_x) / (right_x - left_x);

        // 令 y分别为 rect.y 和  rect.yMax
        let p3 = (yMin - left_y) / (right_y - left_y);
        let p4 = (yMax - left_y) / (right_y - left_y);

        let p_l = Math.max(0, p1, Math.min(p3, p4));
        let p_r = Math.min(1, p2, Math.max(p3, p4));

        let l_x = Math.floor((1 - p_l) * left_x + p_l * right_x);
        let l_y = Math.floor((1 - p_l) * left_y + p_l * right_y);
        let r_x = Math.floor((1 - p_r) * left_x + p_r * right_x);
        let r_y = Math.floor((1 - p_r) * left_y + p_r * right_y);

        if (l_x > xMax || r_x < xMin) {
            return false;
        }

        let ret_min_y = Math.min(l_y, r_y);
        let ret_max_y = Math.max(l_y, r_y);

        if (ret_min_y > yMax || ret_max_y < yMin) {
            return false;
        }

        // 由于浮点数的原因.....
        l_x = cc.math.clamp(l_x, xMin, xMax);
        r_x = cc.math.clamp(r_x, xMin, xMax);
        l_y = cc.math.clamp(l_y, yMin, yMax);
        r_y = cc.math.clamp(r_y, yMin, yMax);

        if (flip) {
            v1.x = r_x;
            v1.y = r_y;
            v2.x = l_x;
            v2.y = l_y;
        } else {
            v1.x = l_x;
            v1.y = l_y;
            v2.x = r_x;
            v2.y = r_y;
        }

        return true;
    },

    /**
     * 对 点 v1 v2 进行裁剪
     * @param v1
     * @param v2
     * @param rect
     * @return {boolean} true 表示裁剪成功,更新v1 v2.  false 表示在区域外.
     */
    clipLine3d(v1, v2, rect) {
        rect = rect || this.clipRect;
        let x1 = v1.x, y1 = v1.y, x2 = v2.x, y2 = v2.y;
        const xMax = rect.xMax;
        const yMax = rect.yMax;
        const xMin = rect.x;
        const yMin = rect.y;

        if (debugUtils.debug) {
            debugUtils.checkInteger(x1);
            debugUtils.checkInteger(y1);
            debugUtils.checkInteger(x2);
            debugUtils.checkInteger(y2);
        }

        // 都在上 下 左 右 一定不裁剪
        if (y1 > yMax && y2 > yMax) {
            return false;
        }
        if (y1 < yMin && y2 < yMin) {
            return false;
        }
        if (x1 < xMin && x2 < xMin) {
            return false;
        }
        if (x1 > xMax && x2 > xMax) {
            return false;
        }

        if (this.isRectContainPoint(x1, y1, rect) && this.isRectContainPoint(x2, y2, rect)) {
            // 不需要裁剪, 取原来的值
            return true;
        }

        if (x1 === x2) {

            if (y1 === y2) {
                return false;
            }

            // 垂直
            let min_y = Math.min(y1, y2);
            let max_y = Math.max(y1, y2);
            if (min_y > yMax || max_y < yMin) {
                // 视口外
                return false;
            }
            let t_y1 = cc.math.clamp(y1, yMin, yMax);
            let t_y2 = cc.math.clamp(y2, yMin, yMax);

            let t1 = (t_y1 - v1.y) / (v2.y - v1.y);
            v1.z = (v2.z - v1.z) * t1 + v1.z;

            let t2 = (t_y2 - v2.y) / (v1.y - v2.y);
            v2.z = (v1.z - v2.z) * t2 + v2.z;

            v1.y = t_y1;
            v2.y = t_y2;
            return true;
        }

        if (y1 === y2) {

            if (x1 === x2) {
                return false;
            }

            // 水平
            let min_x = Math.min(x1, x2);
            let max_x = Math.max(x1, x2);
            if (min_x > xMax || max_x < xMin) {
                return false;
            }

            let t_x1 = cc.math.clamp(x1, xMin, xMax);
            let t_x2 = cc.math.clamp(x2, xMin, xMax);

            let t1 = (t_x1 - v1.x) / (v2.x - v1.x);
            v1.z = (v2.z - v1.z) * t1 + v1.z;

            let t2 = (t_x2 - v2.x) / (v1.x - v2.x);
            v2.z = (v1.z - v2.z) * t2 + v2.z;

            v1.x = t_x1;
            v2.x = t_x2;
            return true;
        }

        //
        let left_x = Math.min(x1, x2);
        let left_y, right_x, right_y;
        let flip; // 表示是否交换
        if (left_x === x1) {
            left_y = y1;
            right_x = x2;
            right_y = y2;
            flip = false;
        } else {
            left_y = y2;
            right_x = x1;
            right_y = y1;
            flip = true;
        }

        // 令 x 分别为 rect.x 和  rect.xMax
        // P = (1-t) * A + t * B
        // t = (P - A) / (B - A)
        let p1 = (xMin - left_x) / (right_x - left_x);
        let p2 = (xMax - left_x) / (right_x - left_x);

        // 令 y分别为 rect.y 和  rect.yMax
        let p3 = (yMin - left_y) / (right_y - left_y);
        let p4 = (yMax - left_y) / (right_y - left_y);

        let p_l = Math.max(0, p1, Math.min(p3, p4));
        let p_r = Math.min(1, p2, Math.max(p3, p4));

        let l_x = Math.floor((1 - p_l) * left_x + p_l * right_x);
        let l_y = Math.floor((1 - p_l) * left_y + p_l * right_y);
        let r_x = Math.floor((1 - p_r) * left_x + p_r * right_x);
        let r_y = Math.floor((1 - p_r) * left_y + p_r * right_y);

        if (l_x > xMax || r_x < xMin) {
            return false;
        }

        let ret_min_y = Math.min(l_y, r_y);
        let ret_max_y = Math.max(l_y, r_y);

        if (ret_min_y > yMax || ret_max_y < yMin) {
            return false;
        }

        // 由于浮点数的原因.....
        l_x = cc.math.clamp(l_x, xMin, xMax);
        r_x = cc.math.clamp(r_x, xMin, xMax);
        l_y = cc.math.clamp(l_y, yMin, yMax);
        r_y = cc.math.clamp(r_y, yMin, yMax);

        if (flip) {
            v1.x = r_x;
            v1.y = r_y;
            v2.x = l_x;
            v2.y = l_y;

            v1.z = (v2.z - v1.z) * p_r + v1.z;
            v2.z = (v2.z - v1.z) * p_l + v1.z;
        } else {
            v1.x = l_x;
            v1.y = l_y;
            v2.x = r_x;
            v2.y = r_y;

            v1.z = (v2.z - v1.z) * p_l + v1.z;
            v2.z = (v2.z - v1.z) * p_r + v1.z;
        }

        return true;
    },

    /**
     * 绘制直线,但是不进行安全检查
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @param color
     * @private
     */
    _line(x1, y1, x2, y2, color) {

        if (debugUtils.debug) {
            debugUtils.checkInteger(x1);
            debugUtils.checkInteger(y1);
            debugUtils.checkInteger(x2);
            debugUtils.checkInteger(y2);
        }

        // 不考虑裁剪
        if (x1 === x2) {
            // 垂直的
            let min = Math.min(y1, y2);
            let max = Math.max(y1, y2);
            for (let i = min; i <= max; ++i) {
                this._pixel(x1, i, color);
            }
            return;
        }

        if (y1 === y2) {
            // 水平
            let min = Math.min(x1, x2);
            let max = Math.max(x1, x2);
            for (let i = min; i <= max; ++i) {
                this._pixel(i, y1, color);
            }
            return;
        }

        // left(start) -> right(end)
        let k = (y2 - y1) / (x2 - x1);
        let el = 0;
        let b = y1 - k * x1;
        if (k >= 1 || k <= -1) {
            let min_y = Math.min(y1, y2);
            let max_y = Math.max(y1, y2);
            for (let i = min_y; i <= max_y; ++i) {
                let nx = (i - b) / k;
                let ix = Math.floor(nx);
                el += (nx - ix);
                if (el >= 0.5) {
                    ix++;
                    el -= 1;
                }
                this._pixel(ix, i, color);
            }
        } else {
            let min_x = Math.min(x1, x2);
            let max_x = Math.max(x1, x2);
            for (let i = min_x; i <= max_x; ++i) {
                let ny = k * i + b;
                let iy = Math.floor(ny);
                el += (ny - iy);
                if (el >= 0.5) {
                    iy++;
                    el -= 1;
                }
                this._pixel(i, iy, color);
            }
        }
    },


    /**
     * 绘制直线,但是不进行安全检查
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @param color
     * @private
     */
    _line3d(v0,v1, color) {
        let x1 = v0.x,y1 = v0.y,z1 = v0.z;
        let x2 = v1.x,y2 = v1.y,z2 = v1.z;
        if (debugUtils.debug) {
            debugUtils.checkInteger(x1);
            debugUtils.checkInteger(y1);
            debugUtils.checkInteger(x2);
            debugUtils.checkInteger(y2);
        }

        // 不考虑裁剪
        if (x1 === x2) {
            // 垂直的
            let min = Math.min(y1, y2);
            let max = Math.max(y1, y2);
            let dis = max - min;

            let flip = (min === y2);
            let start_z = flip ? z2:z1;
            let end_z = flip? z1:z2;
            let dis_z = end_z - start_z;
            for (let i = min; i <= max; ++i) {
                let t = (i - min) / dis;
                let z = dis_z * t + start_z;
                this._pixel3d(x1, i,z, color);
            }
            return;
        }

        if (y1 === y2) {
            // 水平
            let min = Math.min(x1, x2);
            let max = Math.max(x1, x2);
            let dis = max - min;

            let flip = (min === x2);
            let start_z = flip? z2:z1;
            let end_z = flip? z1:z2;
            let dis_z = end_z - start_z;
            for (let i = min; i <= max; ++i) {
                let t = (i - min) / dis;
                let z = dis_z * t + start_z;
                this._pixel3d(i, y1,z, color);
            }
            return;
        }

        // left(start) -> right(end)
        let k = (y2 - y1) / (x2 - x1);
        let el = 0;
        let b = y1 - k * x1;
        if (k >= 1 || k <= -1) {
            let min_y = Math.min(y1, y2);
            let max_y = Math.max(y1, y2);
            let dis = max_y - min_y;
            let flip = (min_y === y2);
            let start_z = flip?z2:z1;
            let end_z = flip?z1:z2;
            let dis_z = end_z - start_z;
            for (let i = min_y; i <= max_y; ++i) {
                let nx = (i - b) / k;
                let ix = Math.floor(nx);
                el += (nx - ix);
                if (el >= 0.5) {
                    ix++;
                    el -= 1;
                }

                let t = (i - min_y) / dis;
                let z = dis_z * t + start_z;
                this._pixel3d(ix, i,z, color);
            }
        } else {
            let min_x = Math.min(x1, x2);
            let max_x = Math.max(x1, x2);
            let dis = max_x - min_x;
            let flip = (min_x === x2);
            let start_z = flip?z2:z1;
            let end_z = flip?z1:z2;
            let dis_z = end_z - start_z;
            for (let i = min_x; i <= max_x; ++i) {
                let ny = k * i + b;
                let iy = Math.floor(ny);
                el += (ny - iy);
                if (el >= 0.5) {
                    iy++;
                    el -= 1;
                }
                let t = (i - min_x) / dis;
                let z = dis_z * t + start_z;
                this._pixel3d(i, iy,z, color);
            }
        }
    },


    drawLines(lstPoint, color, isLoop = false) {
        let len = lstPoint.length;
        if (len < 2) {
            return;
        }
        for (let i = 0; i < len - 1; +i) {
            let p0 = lstPoint[i];
            let p1 = lstPoint[i + 1];
            this.drawLine(p0.x, p0.y, p1.x, p1.y, color);
        }
        if (isLoop && len > 2) {
            let last = lstPoint[len - 1];
            let first = lstPoint[0];
            this.drawLine(last.x, last.y, first.x, first.y, color);
        }
    },

    // 绘制多边形
    drawPolygon(lstPoint, color) {
        this.drawLines(lstPoint, color, true);
    },

    clear() {
        this.data.fill(0, 0, this.data.length);

        // 清除深度缓存
        if (this.bDepthTest) {
            this.depthArr.fill(1, 0, this.depthArr.length);
        }
    },

    /**
     * 逆时针
     * @param v0
     * @param v1
     * @param v2
     */
    triangle_flat(v0,v1,v2,color){

        // TODO:暂时不考虑z
        // 是否水平共线
        if(v0.y === v1.y && v1.y === v2.y){
            this.drawLine3d(v0,v1,color);
            this.drawLine3d(v1,v2,color);
            this.drawLine3d(v2,v0,color);
            return;
        }

        // 是否垂直共线
        if(v0.x === v1.x && v1.x === v2.x){
            this.drawLine3d(v0,v1,color);
            this.drawLine3d(v1,v2,color);
            this.drawLine3d(v2,v0,color);
            return;
        }

        // 判断是否是平顶三角形
        if(v0.y === v2.y){

        }else{

        }
    },
};





